{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torchvision import datasets\n",
    "from matplotlib import pyplot as plt\n",
    "import torch.nn as nn\n",
    "from torchvision import transforms\n",
    "import torch.optim as optim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Files already downloaded and verified\n",
      "Files already downloaded and verified\n",
      "Files already downloaded and verified\n",
      "Files already downloaded and verified\n"
     ]
    }
   ],
   "source": [
    "## 这里数据用cifar10\n",
    "\n",
    "data_path=r'../Data'\n",
    "# 原始数据\n",
    "cifar10=datasets.CIFAR10(data_path,train=True,download=False,transform=transforms.ToTensor())\n",
    "\n",
    "# 训练数据\n",
    "transformed_cifar10 = datasets.CIFAR10(data_path,train=True,download=True,transform=transforms.ToTensor())\n",
    "imgs = torch.stack([img_t for img_t,_ in transformed_cifar10],dim=3)\n",
    "mean = imgs.view(3,-1).mean(dim=1)\n",
    "std = imgs.view(3,-1).std(dim=1)\n",
    "transformed_cifar10=datasets.CIFAR10(data_path,train=True,download=True,transform=transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize(mean=mean,std=std)\n",
    "]))\n",
    "\n",
    "transformed_cifar10_val = datasets.CIFAR10(data_path,train=False,download=True,transform=transforms.ToTensor())\n",
    "imgs = torch.stack([img_t for img_t,_ in transformed_cifar10],dim=3)\n",
    "mean = imgs.view(3,-1).mean(dim=1)\n",
    "std = imgs.view(3,-1).std(dim=1)\n",
    "transformed_cifar10_val=datasets.CIFAR10(data_path,train=False,download=True,transform=transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize(mean=mean,std=std)\n",
    "]))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 卷积思想\n",
    "对于一张图片来说，前面的模型，利用的思想是将32\\*32\\*3的数据打成一维向量，作为全连接进行参数训练。\n",
    "\n",
    "但从人的视角来看，它是一张具有含义的图片，即每个数据的前后左右都有一定的相关性，比如我知道这幅图是一个人，我在第一行看到了代表眼睛的数据。那么我可以断定后面一定会有包含鼻子、嘴巴等的数据。\n",
    "\n",
    "但如果直接将保留位置关系的数据（即原数据）打成一维向量，则会失去原有的位置信息。（数据的相互位置也可以作为一种信息），而打成一维向量以后则失去了这种信息。\n",
    "\n",
    "因此，从卷积的思想，则是将这些相对位置信息进行保留作为训练参数的一部分。故就有比较强的泛化能力\n",
    "\n",
    "\n",
    "### 卷积特征\n",
    "- 邻域的局部操作\n",
    "- 平移不变性\n",
    "- 模型的参数大幅减少\n",
    "\n",
    "\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 卷积实战\n",
    "\n",
    "torch.nn提供一维、二维、三维的卷积\n",
    "- nn.Conv1d用于时间序列\n",
    "- nn.Conv2d用于图像\n",
    "- nn.Conv3d用于体数据和视频"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([16, 3, 3, 3]), torch.Size([16]))"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 这里我们选用Conv2d\n",
    "conv = nn.Conv2d(3,16,kernel_size=3) #这个卷积模块有3个输入特征（RGB通道），输出特征可以选取任意，这里选用16个通道 \n",
    "# kernel=3 ，对于2d来说 size=3*3\n",
    "# 卷积层的 权重参量 形状\n",
    "conv.weight.shape,conv.bias.shape"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上述参数权重说明，w：out_ch\\*in_ch\\*3\\*3\n",
    "偏置张量 为16 \n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 3, 32, 32]), torch.Size([1, 16, 30, 30]))"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "img,_=cifar10[0]\n",
    "output=conv(img.unsqueeze(0))\n",
    "img.unsqueeze(0).shape,output.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x1ec87529130>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGdCAYAAAC7EMwUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAvmUlEQVR4nO3df2zd9X3v8df57WP7+CRO4l+JCS4krCWQ3RIKySgEOiI8jQtNJ9EiVUHbUCk/pCit2AK6Ipo0gphA9Coj27peBhoMpDtgSFAgu5BkvWmmhAsig46GEsAhcUwS//bx+fm9f7BYNQR4v4PNJ3GeD+lI5PjN25/vj3Pe/trnvE4siqJIAAAEEA+9AADA6YshBAAIhiEEAAiGIQQACIYhBAAIhiEEAAiGIQQACIYhBAAIJhl6AR9Xq9V04MAB5XI5xWKx0MsBADhFUaTh4WF1dHQoHv/sa52TbggdOHBAnZ2doZcBAPiCenp6tGDBgs+smbYh9OCDD+qv/uqvdPDgQZ177rl64IEH9M1vfvNz/79cLidJuuAbFymZtC1vcLDfvK5MvGaulaTZaXuq0YLZ9a7ec5vt9XPyDa7e6XjKXJvIZF29lUi4yvsHBs215YovRWpWPm+ujVfLrt7FUtFcOz5ur5WkumzGVV9V1VxbKIy6ejflc/biyL4OSSqV7Ps84Xw6SjjOw8aGRlfvhnrfYzmZqjPXjhdLrt5RzPFXk7hvH5ZK9rVUIvtvpsaLJf2P//noxPP5Z5mWIfTEE09o7dq1evDBB/V7v/d7+tu//Vt1d3frzTff1BlnnPGZ/++xX8Elk0nzEPKcjIm471d8yYT9STGd8j05Z1L23V+Xtg8VSUon7PXJjK+3Er7TpuBYezzuG0J1jrXHfc+fisnxA0vN19x7PKuOP9/Wqr7j49mHinx/Ro7LfjwT8u0Tz+M+6zzHs3VpV30qZa/3/pVhOodQwrEWzxA6xvInlWl5YcL999+vP/mTP9Gf/umf6qtf/aoeeOABdXZ2avPmzdPx7QAAp6gpH0KlUkmvvPKKVq1aNen+VatWaceOHZ+oLxaLGhoamnQDAJwepnwIHT58WNVqVa2trZPub21tVW9v7yfqN27cqHw+P3HjRQkAcPqYtvcJffx3gVEUHff3g+vXr9fg4ODEraenZ7qWBAA4yUz5CxPmzp2rRCLxiauevr6+T1wdSVImk1Em43ulEABgZpjyK6F0Oq0LLrhAW7ZsmXT/li1btGLFiqn+dgCAU9i0vER73bp1+v73v69ly5Zp+fLl+ru/+zu9//77uummm6bj2wEATlHTMoSuu+46HTlyRH/xF3+hgwcPasmSJXruuee0cOHC6fh2AIBTVCyKIt+7A6fZ0NDQR6+Ua25W7HMyh44ZOHzY3L/Z/sZmSVLXHPv/sKjN8c5zSWcubDHX1mV8vzmNqvbDGsV8b8wbG/e943usYE8TKFd9iRZJx7vt6pK+U71Ssa8l4XyToPfvoGPj9hSESs13fObOnWOujfvej61y0X7ss0nfg7PoSB6oViuu3vX1voSSmCOhJOZ4I7kkyfg8KElj475UkErZkWiRtJ+zxXJF9z25S4ODg2pqavrMWlK0AQDBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBTEt23FSoS8YUjxsjWRwJKAsdMTySdGZr3lzbMq/Z1TvriAaxfFb7bysUx82142V7tIokRc61pLNZe3HFF60T1exrzzfXu3pXyva1pFOObZRUrbrKlUg7IlNK9mMvSeWK/XjWO9YhSckG+36pc/auxOxRRvHIFwdVke8cd6RHqbHBdx6OjI6Za8sVX2yP9SlWkoaHBs21pbL9BOdKCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABDMyZsdF6sqHrPlPeVy9s1YPH+2ax1zsglzbarmy+waOVoy11Zrvp8XCmMVc2087WqtplmNrvqkIxNsYHDY19txBjfnfJldw0P2bLLSuL1WkgrjvoyvyJFl1thgzySUpHKpYK6NV31PGamM/dhXq759knQEthWLvt7plO9BEa/ZH2/FkX5Xb1XtGYYZ+9OVJKlSs2fqDY7acxpLFXtfroQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMGctLE9szIJJeK2GZl1RIPkG7KudcxrSplrq7Wqq7enOpF05nEY950kFWvOuBRPVo6kZGSP8KgW7REykhQl7NvZ1zfg6l0t24/Q8NiYq/dY1R7ZJEmN2SZ7cdF3HibkiFiJ2SNkJCmRqTPXFkZ9sVf1Kfs+SUa+dY+P+45PoWyP7anJt5aBEft+GRjzPZZHHPFe42X7Y61SJbYHAHAKYAgBAIJhCAEAgmEIAQCCYQgBAIJhCAEAgmEIAQCCYQgBAIJhCAEAgmEIAQCCYQgBAII5abPj5ubrlDTmguVS9ly1ujpfBls8Yc95ymZ9uXTlij3jq6aYq3cU2bOvShVfllW15MunqkX2+siZqRYl0+ba4dKoq3e1aj9XxhxZWZIvW0uShkft+/CDo77tTMXta2ka8Z2H5d7D5trCoC9/74y5Z5trW1oWuHrHcoOu+mL/EXPtyIjv+AwO27PjDg/6shff7bFvZzVhHxc1R1YfV0IAgGCmfAht2LBBsVhs0q2trW2qvw0AYAaYll/HnXvuufrXf/3XiX8nEs6PIQAAnBamZQglk0mufgAAn2ta/ia0d+9edXR0qKurS9/97nf1zjvvfGptsVjU0NDQpBsA4PQw5UPooosu0iOPPKIXXnhBP/3pT9Xb26sVK1boyJHjv3pk48aNyufzE7fOzs6pXhIA4CQ15UOou7tb3/nOd3Teeefp93//9/Xss89Kkh5++OHj1q9fv16Dg4MTt56enqleEgDgJDXt7xNqaGjQeeedp7179x7365lMRplMZrqXAQA4CU37+4SKxaJ+9atfqb29fbq/FQDgFDPlQ+jHP/6xtm3bpn379unf//3f9Ud/9EcaGhrSmjVrpvpbAQBOcVP+67j9+/fre9/7ng4fPqx58+bp4osv1s6dO7Vw4UJXn7a59Uonbe8vakpXzH0b6+0xL5IUc0TOSL74m1hkj0spFnyRJnFHzM+cXN7Vu6GhzlU/NGiPbsk3Nbl6D4/bj897H9jXIUkjRfv729K+FB7Nr/c99JIpexzLu0cGXL2LkX07UzHfOZ5vyplrV3xtmav30EF77FU05lz33JSrvjhmP54jI76f/TMp+1o62+z7W5JaWlrNtYeG7PFBlWpN7//HflPtlA+hxx9/fKpbAgBmKLLjAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBTPtHOZyo2Y1ZZVK2TKtkacDcN5PybXJ9pt5cWyx4cuakcs2eeTdr1mxX7yiyZ2WVqr6fRcple4aUJNU3NpprD3xYdPX+zXuD5toPh+37W5LGHOULs/b8NUm69pu/66pf0G7fh//7lU//JOPj+eXbvebaSq3k6p2M28/D4YEPXb3HRuznSi7ny4JT1Z69KEl1dfb+6TrfuVIfs/euVH3n+BmdHeba3NFhc22pXNV2Y3YcV0IAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGBO2tieebObVZe2La9w1B4jE4/5NnlkzB7FUyj5IjOSMXt8x1i56urt+emiUPZFscya3eSqL1Xt0S3v7D/g6n10yL5fomTa1TuRsO/Fpjrf8WlJ2iNQJKnuqD2iZlFTm6v3wWb7dh4a6HP1Lo7Zz61Xf/1rV+94pWauLTf4zlnlW331cfvzSj5vjwKTpFzN/vgZL/miw6LSkLn2zHkNjnXYnwu5EgIABMMQAgAEwxACAATDEAIABMMQAgAEwxACAATDEAIABMMQAgAEwxACAATDEAIABMMQAgAEc9Jmx82aM1fZTMpUO7sxa+4bj9t6HjMw1G+uLY+OuHrHq/a8sZrsOVmSFKXsh7axsc7Vuyxf/a/esWeCjRZHXb3r6jL2WmMW4THZBnvG1+yELzfwlbcPueorJfvai3lfdty82fbjGZMvg61csec6jpUKrt6jY/ZMtVLFd3xizjxFxeylqbijWFIUt2dMppK+c7xStGcSRo4MSE8tV0IAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYE7a7DjFk5Ix5y2W8uXBeWTq7L3r1eDqnXT8DBCP+35eKDuy5jLZvKv34d5hV/3YYXv+3leafbl0RXs0meocWXCSdM5Z8821cc9CJFUSvnN2yJFhmEwMunrn0vbzds7ss1y9z1p0hrl23/u7XL3/89cfmGvTSXtGmiRFkS8HslKxP5XGk2lX71Tafq7Uar6MyZoj9C4Wsz8HeWq5EgIABOMeQtu3b9fVV1+tjo4OxWIxPf3005O+HkWRNmzYoI6ODmWzWa1cuVJvvPHGVK0XADCDuIfQ6Oioli5dqk2bNh336/fee6/uv/9+bdq0Sbt27VJbW5uuvPJKDQ/7foUDAJj53H8T6u7uVnd393G/FkWRHnjgAd15551avXq1JOnhhx9Wa2urHnvsMf3gBz/4YqsFAMwoU/o3oX379qm3t1erVq2auC+Tyeiyyy7Tjh07jvv/FItFDQ0NTboBAE4PUzqEent7JUmtra2T7m9tbZ342sdt3LhR+Xx+4tbZ2TmVSwIAnMSm5dVxsdjkl/1FUfSJ+45Zv369BgcHJ249PT3TsSQAwEloSt8n1Nb20Wfb9/b2qr29feL+vr6+T1wdHZPJZJTJZKZyGQCAU8SUXgl1dXWpra1NW7ZsmbivVCpp27ZtWrFixVR+KwDADOC+EhoZGdHbb7898e99+/bptddeU3Nzs8444wytXbtWd999txYtWqRFixbp7rvvVn19va6//vopXTgA4NTnHkK7d+/W5ZdfPvHvdevWSZLWrFmjf/iHf9Dtt9+uQqGgm2++Wf39/brooov04osvKpfLub7P+HhFimyRErFywdG54lrH6Kj91Xqlsu/CshK3R9SMjPneZzXkqJ/f6TsNoopvLQvn2qNBzurwxdmMjdt7z1+81NU7HdmjePoHy67e2VlzXPU6kjCXdra1f37RbxkYHTXXfuV3Frl6N822RyU1zf6qq3f/h/bzsH/QF2WUckQZSVI8sv9JoVyrunp7kniqZd/zW9z+8FEURdNS6x5CK1eu/MxvEIvFtGHDBm3YsMHbGgBwmiE7DgAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEAxDCAAQzJR+lMNUqsaqqsZsMzKq2vOSPJlGkpSty5prG3P2nCxJOvChPfNu3/4PXb2TKft2pg8dcPUeP+Rby6IWex7ct1b6ssl+88FRc21u/jxX77lz2sy1fR8ecvWeNcuZTVaz78N03J4zJ0l9H35grk3WDbh6fzhw0Fz7wcERV+9Uyv54m9XkCGCTVCj4nieipP3n+ZgnsE1SzZE1F/+Uz2379LXY11317RIzroQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMGctLE9+XyDsnVpU20laY/tGRkZd60jKtsjMwaHB12933vfHvUyMuKLNMnW2X++OLhvyNW71Xhcjpk/f6G5dlZHl6t3atgRx1Jnj76RpAVLv2Fv3WuPvpGkbMUXfVSV/bwdHfWd4+319jijUtUXfxNraDTXLmjocPXOzbLHKg0f6XX17jt0xFVfjtnPrfFS0dVbcXteTkOmztW6VLA/r6TS9m2syh4fxJUQACAYhhAAIBiGEAAgGIYQACAYhhAAIBiGEAAgGIYQACAYhhAAIBiGEAAgGIYQACAYhhAAIJiTNjtuZPCoKuO2rKJkadjcNxVzzt2EvTSZcBRLGhuxZ83NzjW4es9qsGdIFfp92XEtHXNc9fPPv8xc+x/7S67ev37bXr+ivdnVe2DA3rv1rKWu3nGNuepLRXvW3KzIl+821GfPScuWyq7e7c32fT5Qzbh6p86fba4tDBx09f6/zz3jqt/fYz8+CUcG20fsOWwFe8ycJKnsuA6Jl+3Hfrxsz/PkSggAEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEMxJG9sTj0kJY1pFtTBi7hs5IjAkKS57/EQ15ovt6XckoAwN+fI4oqI9cqY974sEuvDyy131C8652Fz75EP/y9W7raHRXJsoFVy9P3jnN/Z1fOVrrt51c8521TdE9miqsaN9rt7Zmj3+plTwxQ0dHrbXz5rX5eo9p+1Mc21hpMnVO+4rVzU9bq6NxX3PQeWy/bEcq1RdvWORvb5SsY+LctX+fMWVEAAgGIYQACAY9xDavn27rr76anV0dCgWi+npp5+e9PUbbrhBsVhs0u3ii+2/jgEAnD7cQ2h0dFRLly7Vpk2bPrXmqquu0sGDByduzz333BdaJABgZnK/MKG7u1vd3d2fWZPJZNTW1nbCiwIAnB6m5W9CW7duVUtLixYvXqwbb7xRfX2f/mqdYrGooaGhSTcAwOlhyodQd3e3Hn30Ub300ku67777tGvXLl1xxRUqFovHrd+4caPy+fzErbOzc6qXBAA4SU35+4Suu+66if9esmSJli1bpoULF+rZZ5/V6tWrP1G/fv16rVu3buLfQ0NDDCIAOE1M+5tV29vbtXDhQu3du/e4X89kMspkfJ8tDwCYGab9fUJHjhxRT0+P2tvbp/tbAQBOMe4roZGREb399tsT/963b59ee+01NTc3q7m5WRs2bNB3vvMdtbe3691339Udd9yhuXPn6tvf/vaULhwAcOpzD6Hdu3fr8t/KDjv295w1a9Zo8+bN2rNnjx555BENDAyovb1dl19+uZ544gnlcjnX94lFH90sqmV7CFss7rv4SzrKo4IjDE5SrGavbZ5T7+rdVm/PvPv6ssWu3l9d4XvzcX+fPdsvUxl09f7KggXm2ppnh0tqa5lnrq2M2/e3JI0N2PPAJKlUsfcvF3wP66rs+Xu/+WC/q/ee/9htrl1xsW+fzGmbY64dGvbl6aV8DzfNPdOev1hzPgdVS458N0dmpCQNfjhgri0O23dKsWxfs3sIrVy5UlH06dPhhRde8LYEAJymyI4DAATDEAIABMMQAgAEwxACAATDEAIABMMQAgAEwxACAATDEAIABMMQAgAEwxACAAQz7R/lcKJqlapqCduMLBTtmWDpBntOliQlkylzbSLuy206u222ubYu6/t54cyF9s9kWnrJ5Z9f9FvazznfVf/aLx8y157Rad8nktR27nnm2vS8s1y9k/V5c+3YuD0fT5IKQ8Ou+kMHesy1/Yd8+W7V8pi5Npurc/WeO9f++Ok58Kqrd2v7fHNtZcx3fKLC8T+E89PERvvNtdWo4FuLNURTUjZj39+SlG6z1w9lYuba8ZK9lishAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwJ21sTyqRVCphW17/sD12pDpuj5OQpGx91lybiNvjNSSpZU69ubbn4ICr91lfv8pcu+A8e+1HfNE65eFRc20+Z4/KkaR5i3/XXDuabHb1fuPVXebaYsG+jZI0NDTgqj/8wfvm2kTVFx9VV2d/GpjfZY/KkaTzF59trq0kGly9U4lZ9tp02dU7OT7uqh977wNzba1SdfWuOC4VRhIJV+/6OfZ93toxx1xbGLdvI1dCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGAYQgCAYBhCAIBgGEIAgGBO2uy40nhR8Zotf6g+Y9+MWJ0vWykVr5hro6q9VpKyjfa1/Pfr/rur94rub5lrm+a2unofeudXrvqEYx8ODA+6en/47lvm2gPDvsyurU8/ba5tzKZcvceLI676tlZ7pl5TzpfBtm9/j7m25DiWktTccaa5dvF5F7h6q5oxlx4d2O9qPebMmOwv2PdLLPI97Y4XaubakciXXxmN2DPyvjrL3nfcEV/IlRAAIBiGEAAgGIYQACAYhhAAIBiGEAAgGIYQACAYhhAAIBiGEAAgGIYQACAYhhAAIJiTNranFpVUi4xxFcZ4H0mKVewRGJJUicr23jFfZEZdpslc+7sX+CJNMil7jMybr73q6t1/4Deu+mLRHg0y3H/U1bvn7TfNtSNR1tU7VbWvuzHpi4NqqvNF68ybbY/tOXio19W7Uraf42PDvrihnn3vO6rfcPUeGRk219YlfY/NSqbFVX+kYn8sZ7N1rt71Oft5m03ao4wkaXhsyFxbqdmjiSqO52SuhAAAwbiG0MaNG3XhhRcql8uppaVF1157rd56a3KAZBRF2rBhgzo6OpTNZrVy5Uq98YbvJxwAwOnBNYS2bdumW265RTt37tSWLVtUqVS0atUqjY6OTtTce++9uv/++7Vp0ybt2rVLbW1tuvLKKzU8bL90BgCcHlx/E3r++ecn/fuhhx5SS0uLXnnlFV166aWKokgPPPCA7rzzTq1evVqS9PDDD6u1tVWPPfaYfvCDH0zdygEAp7wv9DehwcGPPvulublZkrRv3z719vZq1apVEzWZTEaXXXaZduzYcdwexWJRQ0NDk24AgNPDCQ+hKIq0bt06XXLJJVqyZIkkqbf3o1fltLZO/pC01tbWia993MaNG5XP5ydunZ2dJ7okAMAp5oSH0K233qrXX39d//RP//SJr8Vikz+VMIqiT9x3zPr16zU4ODhx6+mxf8ojAODUdkLvE7rtttv0zDPPaPv27VqwYMHE/W1tbZI+uiJqb2+fuL+vr+8TV0fHZDIZZTK+17YDAGYG15VQFEW69dZb9eSTT+qll15SV1fXpK93dXWpra1NW7ZsmbivVCpp27ZtWrFixdSsGAAwY7iuhG655RY99thj+pd/+RflcrmJv/Pk83lls1nFYjGtXbtWd999txYtWqRFixbp7rvvVn19va6//vpp2QAAwKnLNYQ2b94sSVq5cuWk+x966CHdcMMNkqTbb79dhUJBN998s/r7+3XRRRfpxRdfVC6Xm5IFAwBmjlgURb5QpWk2NDSkfD6vjX98ierSthl5dP+75v7p7CzXeqoVe65WWfZsJUk64+xF9t4xX+5Zc2vX5xf9l5Z23ysSS2ODrvrRvn323kc8WWPSGV1nmGvLKV9e26/3/Ie5tjDc7+qdrff9HTSWsv/mfHS86OodyZ57V4qO/wKjTxOTPcOwMWvPX5OkYqVgL075sv2qcV/9B8Pv2IsbSq7e9Rn7tUJdzfdn/qzS5tqvnr/YXDtWKOu6HzyjwcFBNTV99nElOw4AEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEAxDCAAQDEMIABAMQwgAEMwJfZTDl6FWi6lWs0WEpJP2iI26ZM23kLg9piRK+GJhaiV7JNDhw8f/UMBPM/KhvT5b9n2abc0R8yJJzbPnmGtndcxz9a5U7RE1Hxzw7cNI9kSreNz3UCpVfBFPiZg9/qahrt7Vu+J4SCQ8xZIUs+/DaskXBxU3Pj9I0tCYL1aplHFEAknKddjPw9HsgKv3cM0e8zM+6ruumNP0FXPt3Bb743h01L5mroQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwZy02XHxWEbxmG15dZmsuW8kX2ZXQ9aew9WQm+vqPVYeN9fOyaVdvZOO7SwNHnL1rsV9axlL2fPGWlu7fGsp2TOqzjl/gav3jpf/j7m2FI25eqdi9twzSSqM2Ps35ZpcvdNJ+9NAIubLjhsZt5/j+w768t0GBuzneDE26uo9b7Hv5/P5s+zPQaXI9/jpP2w/9ulxe8agJDXMt+fBFcaq9tqCvZYrIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMCdtbE8qGVM6aZuRY8WiuW+irsG1jloiY64dKxdcvROpyFybSdtjQSQplbJvZ7o+7+qdb/Ltw94P7bFAY/N90TotnWebaz/oO+zqfe6Fv2euHfnwgKv3O79+w1U/OjJgrk0mfOdhPm+P+YnJF9tz8AP7fnn/vUFX73jGfh42tdrjtyRpXrMv+ijmiCeKHfU9fmb325+m57c0u3ovmGV/vL39Zq+5tjBeNtdyJQQACIYhBAAIhiEEAAiGIQQACIYhBAAIhiEEAAiGIQQACIYhBAAIhiEEAAiGIQQACIYhBAAI5qTNjmuZE1d9nW1Glo8cMfctVH3ZV6Oj9tooXnX1Tibtu7+paY6rdzqVMtcWRodcvbMp52lTstfv3rHD1for59hz6fbvt2dfSVI8HjPX1mfs+1uSEo5MQknKZu15Y6Mjvuy4QsFeX6mUXL0bs/btXPHfFrt61+Xs+W6VRMXVu1oec9UXeuzZcfHhOlfvlvqcufa/LT7X13tWq7n2lYP7zLXjJfv+5koIABCMawht3LhRF154oXK5nFpaWnTttdfqrbfemlRzww03KBaLTbpdfPHFU7poAMDM4BpC27Zt0y233KKdO3dqy5YtqlQqWrVqlUY/9jurq666SgcPHpy4Pffcc1O6aADAzOD65f7zzz8/6d8PPfSQWlpa9Morr+jSSy+duD+TyaitrW1qVggAmLG+0N+EBgc/+hCq5ubJH6S0detWtbS0aPHixbrxxhvV19f3qT2KxaKGhoYm3QAAp4cTHkJRFGndunW65JJLtGTJkon7u7u79eijj+qll17Sfffdp127dumKK65Q8VM+/XTjxo3K5/MTt87OzhNdEgDgFHPCL9G+9dZb9frrr+sXv/jFpPuvu+66if9esmSJli1bpoULF+rZZ5/V6tWrP9Fn/fr1Wrdu3cS/h4aGGEQAcJo4oSF022236ZlnntH27du1YMFnf0Z5e3u7Fi5cqL179x7365lMRpmM7z0TAICZwTWEoijSbbfdpqeeekpbt25VV1fX5/4/R44cUU9Pj9rb2094kQCAmcn1N6FbbrlF//iP/6jHHntMuVxOvb296u3tnXjH9cjIiH784x/rl7/8pd59911t3bpVV199tebOnatvf/vb07IBAIBTl+tKaPPmzZKklStXTrr/oYce0g033KBEIqE9e/bokUce0cDAgNrb23X55ZfriSeeUC5nj54AAJwe3L+O+yzZbFYvvPDCF1rQMQsWpNWYteVx5WP2LKa3e3yZUIc+/Oxt/m2lqu9vW42N9t0/Ojbo6l2tjZhrE84XSR790J7VJ0nDI/YcqfGybzsTkb0+1zjb1ftQ71Fz7f5Re3aYJNUiey6dJLXOs2cHxmplV+/+gX5zbabBd47Pytt/+EwnfOdhseTIakz6sv1Gi761lEbs/Rtqvt5nd9rfc9nR5suY7Nlvz1488qH9ubNYth8bsuMAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMEwhAAAwTCEAADBMIQAAMGc8OcJTbemWSk11tuiMAqOOInZLQnfQhrqzaWHDx3/g/s+zXipZK5NpptcvR2tVXNEbEhSuerbzsGCPRamIeuLhRkfs8flFMYPu3qXHPul6tyHUeQ7D0eG7Od4U1PW1bupKW+uLRR8sVeHj9iPfWNjg6t3LG7/GTpWscdvSVI66duHGXtymNJp37E/8+wzzbWFMd92bt/+prn29V9/+idkf1ylWjPXciUEAAiGIQQACIYhBAAIhiEEAAiGIQQACIYhBAAIhiEEAAiGIQQACIYhBAAIhiEEAAiGIQQACOakzY5L1CWVrLMtr64pbe7b3Oibu8mCPSctlbXnJUnSUL9j91d9687Wtdhbp3zrrhYHXPXpevt2ppL2YylJiYQ9268Y+bazVLYH8EVRzNU75ov4UlSyZ+RV7aWSpFTSltEoSUr7sv0G+u3ZcYVS2dU7P8uep5h05MxJUtx5Ho6pYq49dHjY1bt/xN57eHTQ1ftft/6nufaQIzawVrOf4FwJAQCCYQgBAIJhCAEAgmEIAQCCYQgBAIJhCAEAgmEIAQCCYQgBAIJhCAEAgmEIAQCCOWlje0ZHkorVjHEiiUZz38YGX6ZJKmuPn2jI1Ll65/P2GJmRoYKr98jQIXvtWNXVuzzuq8+l55hr61KOCBlJlaI9VimZ9P3MlXaUpzIJV+9YzLeW+kb7QzXufFRXqvZYmHTW17xplj1W6ehRX5zNsCOGqanZfg5K0ljFHtkkSXvfPWKu/c89Pa7erc32eKLWBfb9LUmK2/fh3HzOXFut1fRev+25lishAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAnbXbcgR6p3hjFVhywZ7bl5tlzsiSpLls21+btEXaSpOZm++4fGR1z9R4YsNf3H0m7evfbY7IkSYmaPVetFtmz+iSpWnXk2NV8mXeen9Bi8ZirdyLpe+gVqvbVRL5TXKma/RyvjB119a4W7OdhNenLDRwYsfcu+Q69jjqzGt992/6gGDgy6updGrUvvi3f5ur91YXzzbWeXVKu1vT/3rWdK1wJAQCCcQ2hzZs36/zzz1dTU5Oampq0fPly/fznP5/4ehRF2rBhgzo6OpTNZrVy5Uq98cYbU75oAMDM4BpCCxYs0D333KPdu3dr9+7duuKKK3TNNddMDJp7771X999/vzZt2qRdu3apra1NV155pYaHfRHtAIDTg2sIXX311fqDP/gDLV68WIsXL9Zf/uVfqrGxUTt37lQURXrggQd05513avXq1VqyZIkefvhhjY2N6bHHHpuu9QMATmEn/DeharWqxx9/XKOjo1q+fLn27dun3t5erVq1aqImk8nosssu044dOz61T7FY1NDQ0KQbAOD04B5Ce/bsUWNjozKZjG666SY99dRT+trXvqbe3l5JUmtr66T61tbWia8dz8aNG5XP5ydunZ2d3iUBAE5R7iF0zjnn6LXXXtPOnTv1wx/+UGvWrNGbb7458fVYbPJLVaMo+sR9v239+vUaHBycuPX0+D76FgBw6nK/TyidTuvss8+WJC1btky7du3ST37yE/3Zn/2ZJKm3t1ft7e0T9X19fZ+4OvptmUxGmUzGuwwAwAzwhd8nFEWRisWiurq61NbWpi1btkx8rVQqadu2bVqxYsUX/TYAgBnIdSV0xx13qLu7W52dnRoeHtbjjz+urVu36vnnn1csFtPatWt19913a9GiRVq0aJHuvvtu1dfX6/rrr5+u9QMATmGuIXTo0CF9//vf18GDB5XP53X++efr+eef15VXXilJuv3221UoFHTzzTerv79fF110kV588UXlcjn3wqqpOaqmbL+mK6eXmfsWa0XXOuKVw+baurwvumXWPHvc0Oy4L4uleaxmrh04mnX1Hjhsj+GRpMKo/TSrVnwRQorsF/O1in2fSNJ4Ydxcm0771p1I+vbh8Lh97YUR+7olKRWVzLW5uO+xXIvbX+1aLvv+OpBpsEc81RmfS46ZlbbvE0n6imaZa89b2uDqfc75S821Z/7Xn0qsvnGxPfpo/4ERc22xVJH+37umWtdR/9nPfvaZX4/FYtqwYYM2bNjgaQsAOE2RHQcACIYhBAAIhiEEAAiGIQQACIYhBAAIhiEEAAiGIQQACIYhBAAIhiEEAAjGnaI93aLooyiOsXF7bEbBURtLlV3rqdXscTnxMV9sT3LUsZZ41dV7tGCPeRkt+PbJmCNCRpIK4/Z4Fcfu/i/TGNtTtO+XauQ79omq73gWivZ9OF7yHc8ostcnnfFR4yV7fdF77GP2fZKIfDFJxbJvMaWK/XimnL09z4Ujo77IpoLjHC96juV/beOx5/PPEossVV+i/fv388F2ADAD9PT0aMGCBZ9Zc9INoVqtpgMHDiiXy036MLyhoSF1dnaqp6dHTU1NAVc4vdjOmeN02EaJ7ZxppmI7oyjS8PCwOjo6FI9/9m8rTrpfx8Xj8c+cnE1NTTP6BDiG7Zw5TodtlNjOmeaLbmc+nzfV8cIEAEAwDCEAQDCnzBDKZDK66667lMn4PpzqVMN2zhynwzZKbOdM82Vv50n3wgQAwOnjlLkSAgDMPAwhAEAwDCEAQDAMIQBAMKfMEHrwwQfV1dWluro6XXDBBfq3f/u30EuaUhs2bFAsFpt0a2trC72sL2T79u26+uqr1dHRoVgspqeffnrS16Mo0oYNG9TR0aFsNquVK1fqjTfeCLPYL+DztvOGG274xLG9+OKLwyz2BG3cuFEXXnihcrmcWlpadO211+qtt96aVDMTjqdlO2fC8dy8ebPOP//8iTekLl++XD//+c8nvv5lHstTYgg98cQTWrt2re688069+uqr+uY3v6nu7m69//77oZc2pc4991wdPHhw4rZnz57QS/pCRkdHtXTpUm3atOm4X7/33nt1//33a9OmTdq1a5fa2tp05ZVXanh4+Ete6RfzedspSVddddWkY/vcc899iSv84rZt26ZbbrlFO3fu1JYtW1SpVLRq1SqNjo5O1MyE42nZTunUP54LFizQPffco927d2v37t264oordM0110wMmi/1WEangG984xvRTTfdNOm+3/md34n+/M//PNCKpt5dd90VLV26NPQypo2k6Kmnnpr4d61Wi9ra2qJ77rln4r7x8fEon89Hf/M3fxNghVPj49sZRVG0Zs2a6JprrgmynunS19cXSYq2bdsWRdHMPZ4f384ompnHM4qiaPbs2dHf//3ff+nH8qS/EiqVSnrllVe0atWqSfevWrVKO3bsCLSq6bF37151dHSoq6tL3/3ud/XOO++EXtK02bdvn3p7eycd10wmo8suu2zGHVdJ2rp1q1paWrR48WLdeOON6uvrC72kL2RwcFCS1NzcLGnmHs+Pb+cxM+l4VqtVPf744xodHdXy5cu/9GN50g+hw4cPq1qtqrW1ddL9ra2t6u3tDbSqqXfRRRfpkUce0QsvvKCf/vSn6u3t1YoVK3TkyJHQS5sWx47dTD+uktTd3a1HH31UL730ku677z7t2rVLV1xxhYrFYuilnZAoirRu3TpdcsklWrJkiaSZeTyPt53SzDmee/bsUWNjozKZjG666SY99dRT+trXvvalH8uTLkX70/z2xzpIH50gH7/vVNbd3T3x3+edd56WL1+us846Sw8//LDWrVsXcGXTa6YfV0m67rrrJv57yZIlWrZsmRYuXKhnn31Wq1evDriyE3Prrbfq9ddf1y9+8YtPfG0mHc9P286ZcjzPOeccvfbaaxoYGNA///M/a82aNdq2bdvE17+sY3nSXwnNnTtXiUTiExO4r6/vE5N6JmloaNB5552nvXv3hl7KtDj2yr/T7bhKUnt7uxYuXHhKHtvbbrtNzzzzjF5++eVJH7ky047np23n8ZyqxzOdTuvss8/WsmXLtHHjRi1dulQ/+clPvvRjedIPoXQ6rQsuuEBbtmyZdP+WLVu0YsWKQKuafsViUb/61a/U3t4eeinToqurS21tbZOOa6lU0rZt22b0cZWkI0eOqKen55Q6tlEU6dZbb9WTTz6pl156SV1dXZO+PlOO5+dt5/GcisfzeKIoUrFY/PKP5ZS/1GEaPP7441EqlYp+9rOfRW+++Wa0du3aqKGhIXr33XdDL23K/OhHP4q2bt0avfPOO9HOnTujP/zDP4xyudwpvY3Dw8PRq6++Gr366quRpOj++++PXn311ei9996LoiiK7rnnniifz0dPPvlktGfPnuh73/te1N7eHg0NDQVeuc9nbefw8HD0ox/9KNqxY0e0b9++6OWXX46WL18ezZ8//5Tazh/+8IdRPp+Ptm7dGh08eHDiNjY2NlEzE47n523nTDme69evj7Zv3x7t27cvev3116M77rgjisfj0YsvvhhF0Zd7LE+JIRRFUfTXf/3X0cKFC6N0Oh19/etfn/SSyZnguuuui9rb26NUKhV1dHREq1evjt54443Qy/pCXn755UjSJ25r1qyJouijl/XeddddUVtbW5TJZKJLL7002rNnT9hFn4DP2s6xsbFo1apV0bx586JUKhWdccYZ0Zo1a6L3338/9LJdjrd9kqKHHnpoomYmHM/P286Zcjz/+I//eOL5dN68edG3vvWtiQEURV/useSjHAAAwZz0fxMCAMxcDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMAwhAEAwDCEAQDAMIQBAMP8fhvp/Nh+7qI0AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(img.permute(1,2,0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(output[0,0].detach(),cmap='gray')\n",
    "plt.show()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 打Padding\n",
    "\n",
    "零填充以保留输出图像的大小\n",
    "\n",
    "- 我们希望卷积和改变图形大小是分开的操作。\n",
    "- 希望卷积之前和之后，张量的大小是一致的，便于后续将他们相加或取差\n",
    "\n",
    "这样即使在原始图像的角落也可以计算出卷积的输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 3, 32, 32]), torch.Size([1, 1, 32, 32]))"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv = nn.Conv2d(3,1,kernel_size=3,padding=1)\n",
    "output=conv(img.unsqueeze(0))\n",
    "img.unsqueeze(0).shape,output.shape"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 深度和池化技术\n",
    "\n",
    "- 为什么要采用池化技术？\n",
    "\n",
    "设想这样的场景，在一张图片中，有占比特别大的物体，有占比比较小的物体。当适用同一种卷积核时，对于比较小的物体比较容易发现。但对于大物体可能就检测效果欠佳。\n",
    "\n",
    "针对这样的情况，一方面可以用比较大的卷积核。但对于大卷积核来说，又和全连接仿射变换差不多了。同时失去了卷积所有优良特性。\n",
    "\n",
    "- 一种可行的办法就是先 卷积第一次 对图片内的小规模的目标进行检测和学习，然后再对图片进行下采样（从大到小）可以理解为把图片整体缩小。然后再进行卷积，去对大目标进行检测。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nn.Sequential(\n",
    "    nn.Conv2d(3,16,kernel_size=3,padding=1),\n",
    "    nn.Tanh(),\n",
    "    nn.MaxPool2d(2),\n",
    "    nn.Conv2d(16,8,kernel_size=3,padding=1),\n",
    "    nn.Tanh(),\n",
    "    nn.MaxPool2d(2),\n",
    "    ##...\n",
    "    nn.Linear(8*8*8,32),\n",
    "    nn.Tanh(),\n",
    "    nn.Linear(32,2))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 上述Linear 线性层的大小取决于MaxPool2d的预期输出大小：8\\*8\\*8=512\n",
    "\n",
    "为了能够使PyTorch跟踪参数和子模块\n",
    "\n",
    "因此后续适用nn.Module模块进行网络的定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.conv1 = nn.Conv2d(3,16,kernel_size=3,padding=1)\n",
    "        self.act1 = nn.Tanh()\n",
    "        self.pool1 = nn.MaxPool2d(2)\n",
    "        self.conv2 = nn.Conv2d(16,8,kernel_size=3,padding=1)\n",
    "        self.act2 = nn.Tanh()\n",
    "        self.pool2 = nn.MaxPool2d(2)\n",
    "        self.fc1 = nn.Linear(8*8*8,32)\n",
    "        self.act3 =nn.Tanh()\n",
    "        self.fc2 = nn.Linear(32,10)\n",
    "    def forward(self,x):\n",
    "        out = self.act1(self.conv1(x)) #卷积+激活\n",
    "        out = self.pool1(out)# 池化\n",
    "        out = self.act2(self.conv2(out))# 卷积+激活\n",
    "        out = self.pool2(out) # 池化\n",
    "        out = out.view(-1,8*8*8)\n",
    "        out = self.act3(self.fc1(out))  #全连接+激活\n",
    "        out = self.fc2(out)\n",
    "        return out\n",
    "      "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 训练函数\n",
    "def training_loop(n_epochs,optimizer,model,loss_fn,train_loader):\n",
    "    for epoch in range(1,n_epochs+1):\n",
    "        loss_train=0.0\n",
    "        for imgs,labels in train_loader:\n",
    "            imgs = imgs.to(device='cuda')\n",
    "            labels = labels.to(device='cuda')\n",
    "            model = model.to(device='cuda')\n",
    "            outputs = model(imgs)\n",
    "            loss = loss_fn(outputs,labels)\n",
    "            optimizer.zero_grad()\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "\n",
    "            loss_train += loss.item()\n",
    "        if epoch == 1 or epoch % 10 == 0:\n",
    "            print(\"{} Epoch:{}, TrainingLoss:{}\".format(datetime.datetime.now(),epoch,loss_train/len(train_loader)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2023-03-01 22:18:54.505381 Epoch:1, TrainingLoss:0.6173116721003257\n",
      "2023-03-01 22:20:29.872300 Epoch:10, TrainingLoss:0.6086671017396176\n",
      "2023-03-01 22:22:13.705575 Epoch:20, TrainingLoss:0.5993790568788643\n",
      "2023-03-01 22:24:02.271191 Epoch:30, TrainingLoss:0.5915073198659341\n",
      "2023-03-01 22:25:50.930557 Epoch:40, TrainingLoss:0.5851359225599967\n",
      "2023-03-01 22:27:40.554344 Epoch:50, TrainingLoss:0.5783827816662581\n"
     ]
    }
   ],
   "source": [
    "train_loader = torch.utils.data.DataLoader(transformed_cifar10,batch_size=64,shuffle=True)\n",
    "model = Net()\n",
    "model.load_state_dict(torch.load(\"cifar10.pt\"))\n",
    "optimizer = optim.SGD(model.parameters(),lr=1e-2)\n",
    "loss_fn = nn.CrossEntropyLoss()\n",
    "\n",
    "training_loop(\n",
    "    n_epochs=50,\n",
    "    optimizer=optimizer,\n",
    "    model=model,\n",
    "    loss_fn=loss_fn,\n",
    "    train_loader=train_loader\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy train:75.96%\n",
      "Accuracy val:24.03%\n"
     ]
    }
   ],
   "source": [
    "train_loader = torch.utils.data.DataLoader(transformed_cifar10,batch_size=128,shuffle=False)\n",
    "val_loader = torch.utils.data.DataLoader(transformed_cifar10_val,batch_size=128,shuffle=False)\n",
    "\n",
    "def validate(model, train_loader, val_loader):\n",
    "    for name, loader in [(\"train\", train_loader), (\"val\", val_loader)]:\n",
    "        correct = 0\n",
    "        total = 0\n",
    "        with torch.no_grad():\n",
    "            for imgs,labels in loader:\n",
    "                imgs=imgs.to(device='cuda')\n",
    "                labels = labels.to(device='cuda')\n",
    "                model = model.to(device='cuda')\n",
    "                outputs = model(imgs)\n",
    "                _,predicted = torch.max(outputs,dim=1)\n",
    "                total += labels.shape[0]\n",
    "                correct += int((predicted==labels).sum())\n",
    "            print(\"Accuracy {}:{:.2f}\".format(name,correct*100/total)+\"%\")\n",
    "\n",
    "\n",
    "validate(model,train_loader,val_loader)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 保存并加载模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 保存参数\n",
    "torch.save(model.state_dict(),\"cifar10.pt\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<All keys matched successfully>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 加载参数\n",
    "loaded_model = Net()\n",
    "loaded_model.load_state_dict(torch.load(\"cifar10.pt\"))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "e8f28fbeb112014ba6c333544755f206e5d677c1e329d1a6cce6c1b79d7517a3"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
